package models

import (
	"errmsg"
	"errors"
	"fmt"
	"github.com/astaxie/beego"
	"github.com/astaxie/beego/logs"
	"github.com/astaxie/beego/orm"
	"github.com/astaxie/beego/validation"
	"github.com/fwhezfwhez/errorx"
	"time"
	"tools"
)

type Equipment struct {
	Id         string `orm:"column(id);pk" json:"id" form:"id"`
	UserId     string `orm:"column(user_id)" json:"user_id" form:"user_id"`
	Name       string `orm:"column(name)" json:"name" form:"name"`
	Sta        string `orm:"column(sta)" json:"sta" form:"sta"`
	SceneId    string `orm:"column(scene_id)" json:"scene_id" form:"scene_id"`
	Type       int64  `orm:"column(type)" json:"type" form:"type"`
	Password   string `orm:"column(password)" json:"-" form:"password"`
	CreateTime int64  `orm:"column(create_time)" json:"create_time" form:"create_time"`
	Version    string `orm:"column(version)" json:"version"`
	User       *User  `orm:"-" json:"user"`
	Scene      *Scene `orm:"-" json:"scene"`
}

func init() {
	orm.RegisterModel(new(Equipment))
}

func (m *Equipment) TableName() string {
	return "equipment"
}

func NewEquipment() *Equipment {
	return &Equipment{}
}

// 验证数据
func (m *Equipment) Validate() error {
	// 录入数据
	vali := validation.Validation{}
	vali.Required(m.Sta, "sta").Message("请指定设备sta")
	vali.Required(m.Name, "name").Message("请输入设备自定义名称")
	vali.MaxSize(m.Name, 4, "name").Message("设备名称最大为4个字符")
	vali.Required(m.SceneId, "scene_id").Message("请输入设备所在场景")
	vali.Required(m.Type, "type").Message("请输入设备类型")
	if len(m.Id) == 0 {
		vali.Required(m.Password, "password").Message("请输入设备登录密码")
	}
	vali.Range(m.Type, 1, 1, "type").Message("设备类型ID， 1：插座")
	if vali.HasErrors() {
		return vali.Errors[0]
	}

	// 用户放入的场景是否存在
	scene, err := GetSceneById(m.SceneId)
	if err != nil {
		logs.Error(errorx.New(err))
		return errmsg.ErrResponseSystem
	}
	if scene == nil {
		err = errors.New("场景不存在")
		return err
	}

	// 同一scene_id下是否同名
	count, err := GetEquipmentCountByUid(m.UserId, map[string]interface{}{
		"scene_id": m.SceneId,
		"name":     m.Name,
	})
	if err != nil {
		logs.Error(errorx.New(err))
		return errmsg.ErrResponseSystem
	}
	if count > 0 {
		err = errors.New("当前场景下设备重名")
		return err
	}

	return nil
}

func GetEquipmentById(id string, uid ...string) (*Equipment, error) {
	var (
		equipment *Equipment
		err       error
	)

	equipment = &Equipment{Id: id}
	if len(uid) == 0 {
		err = orm.NewOrm().Read(equipment)
	} else {
		sql := "SELECT * FROM user_equipments WHERE id = ? and u = ?"
		err = orm.NewOrm().Raw(sql, id, uid[0]).QueryRow(equipment)
	}
	if err == orm.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		logs.Error(err)
		return nil, err
	}

	equipment.User, _ = GetUserById(equipment.UserId)
	equipment.Scene, _ = GetSceneById(equipment.SceneId)

	return equipment, nil
}

// 根据sta找设备
func GetEquipmentBySta(sta string, uid ...string) (*Equipment, error) {
	var (
		equipment *Equipment
		err       error
	)

	equipment = &Equipment{Sta: sta}
	if len(uid) == 0 {
		err = orm.NewOrm().Read(equipment, "sta")
	} else {
		sql := "SELECT * FROM user_equipments WHERE sta = ? and u = ?"
		err = orm.NewOrm().Raw(sql, sta, uid[0]).QueryRow(equipment)
	}

	if err == orm.ErrNoRows {
		return nil, nil
	}
	if err != nil {
		logs.Error(err)
		return nil, err
	}

	equipment.User, _ = GetUserById(equipment.UserId)
	equipment.Scene, _ = GetSceneById(equipment.SceneId)

	return equipment, nil
}

// 添加设备
func AddEquipment(e *Equipment) error {
	e.Id = tools.GUUID()
	e.CreateTime = time.Now().Unix()
	_, err := orm.NewOrm().Insert(e)
	if err != nil {
		logs.Warn(err)
		return err
	}
	return nil
}

// 删除设备
func DelEquipmentBySta(sta string) error {
	sql := "DELETE FROM equipment WHERE sta = ?"
	_, err := orm.NewOrm().Raw(sql).SetArgs(sta).Exec()
	if err != nil {
		logs.Warn(err)
		return err
	}
	return nil
}

// 设备数据初始化
func InitEquipment(sta string) error {
	var (
		err     error
		content string
		e       *Equipment
	)

	if e, err = GetEquipmentBySta(sta); err != nil {
		logs.Error(err)
		return err
	}
	if e == nil {
		return nil
	}

	// 解除分享
	if err = RelieveFamilyBySta(e.Sta); err != nil {
		logs.Error(err)
		return err
	}

	// 删除延时任务
	if err = DelDelayBySta(e.Sta); err != nil {
		logs.Error(err)
		return err
	}

	// 删除定时任务
	if err = DelTimingBySta(e.Sta); err != nil {
		logs.Error(err)
		return err
	}

	// 删除设备
	if err = DelEquipmentBySta(sta); err == nil {
		content = fmt.Sprintf("您的设备(%s)已经被其他账号移除", e.Name)
		// 推送消息
		PushMessage(e.UserId, content, "message")
	}

	return nil
}

// 修改设备
func UpdateEquipment(e *Equipment) bool {
	c, err := orm.NewOrm().Update(e)
	if err != nil {
		logs.Error(err)
		return false
	}
	if c == 0 {
		return false
	}
	return true
}

// 获取多条设备记录
func GetAllEquipmentByUid(uid string, page int, params ...map[string]interface{}) ([]*Equipment, error) {
	var s []interface{}
	sql := "SELECT * FROM user_equipments WHERE u = ? "
	s = append(s, uid)

	if len(params) > 0 && len(params[0]) > 0 {
		for k, v := range params[0] {
			sql += " and " + k + " = ? "
			s = append(s, v)
		}
	}

	sql += " order by create_time desc"
	if page > 0 {
		row := beego.AppConfig.DefaultInt("page_limit", 20)
		start := (page - 1) * row
		sql += " limit ?, ?"
		s = append(s, start)
		s = append(s, row)
	}

	lists := []*Equipment{}
	num, err := orm.NewOrm().Raw(sql, s).QueryRows(&lists)
	if err != nil {
		logs.Error(err)
		return nil, err
	}

	if num == 0 {
		return nil, nil
	}

	for k, v := range lists {
		lists[k].User, _ = GetUserById(v.UserId)
		lists[k].Scene, _ = GetSceneById(v.SceneId)
	}

	return lists, nil
}

// 获取设备数量
func GetEquipmentCountByUid(uid string, params ...map[string]interface{}) (int, error) {
	var s []interface{}
	sql := "SELECT count(id) FROM user_equipments WHERE u = ? "
	s = append(s, uid)

	if len(params) > 0 && len(params[0]) > 0 {
		for k, v := range params[0] {
			sql += " and " + k + " = ? "
			s = append(s, v)
		}
	}

	count := 0
	err := orm.NewOrm().Raw(sql, s).QueryRow(&count)
	return count, err
}

// 判断用户是否有操作权限
func IsEquipmentAuth(uid, sta string) (bool, error) {
	var count int
	sql := `SELECT count(id) FROM user_equipments WHERE u = ? AND sta = ?`
	if err := orm.NewOrm().Raw(sql).SetArgs(uid, sta).QueryRow(&count); err != nil {
		logs.Error(err)
		return false, err
	}
	if count == 0 {
		return false, nil
	}
	return true, nil
}
